#include <windows.h>

/***********************************************************************************************
 TimeZone conversion structures/macros
************************************************************************************************/

#define RK_CLOCK                TEXT("Software\\Microsoft\\Clock")
#define RV_INDST                TEXT("HomeDST")                        // are we currently in DST
#define RV_AUTODST              TEXT("AutoDST")
#define RV_DSTUI                TEXT("ShowDSTUI") 
#define RV_TIMEZONES            TEXT("Time Zones")
#define RV_DISPLAY              TEXT("Display")
#define RV_TZI                  TEXT("TZI")
#define RV_DLT                  TEXT("Dlt")
#define RV_STD                  TEXT("Std")

// FILETIME (100-ns intervals) to minutes (10 x 1000 x 1000 x 60)
#define FILETIME_TO_MINUTES ((__int64)600000000L)

typedef struct tagTZREG {
    LONG    Bias;
    LONG    StandardBias;
    LONG    DaylightBias;
    SYSTEMTIME StandardDate;
    SYSTEMTIME DaylightDate;
} TZREG;

#define ZoneHasDaylightTime(tzi)    (tzi.DaylightDate.wMonth && tzi.DaylightBias)

//  Returns TRUE if it did change the system time, FALSE otherwise
__declspec( dllexport ) void __stdcall SetTimeZone( LPCWSTR szTimeZone )
{
	
	HKEY hKey = NULL;
	TZREG m_tzReg;
    DWORD m_tzRegSize = sizeof(m_tzReg);
	DWORD lpType;

	TIME_ZONE_INFORMATION m_tziCurrent, m_tziSelected;
	DWORD tzid ;
	BOOL m_fInDST;

	LONG OldBias, NewBias;
    SYSTEMTIME  stOld,stNew;
    DWORD size = 32;

    __int64     ftOld = 0;
    __int64     ftNew = 0;

	//MessageBox(0, szTimeZone, TEXT("Hello"), MB_OK);
	if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szTimeZone, NULL, KEY_READ, &hKey) == ERROR_SUCCESS )	
	{
		RegQueryValueEx(hKey, RV_TZI, NULL, &lpType, (PBYTE)&m_tzReg, &m_tzRegSize);

        m_tziSelected.Bias = m_tzReg.Bias;
        m_tziSelected.StandardBias = m_tzReg.StandardBias;
        m_tziSelected.DaylightBias = m_tzReg.DaylightBias;
        m_tziSelected.StandardDate = m_tzReg.StandardDate;
        m_tziSelected.DaylightDate = m_tzReg.DaylightDate;

		RegQueryValueEx(hKey, RV_DLT, NULL, &lpType, (PBYTE)m_tziSelected.DaylightName, &size);
		RegQueryValueEx(hKey, RV_STD, NULL, &lpType, (PBYTE)m_tziSelected.StandardName, &size);

		RegCloseKey(hKey);

		// get the current time zone
		tzid = GetTimeZoneInformation(&m_tziCurrent);

		// Does the kernel think we're currently in DST?
		m_fInDST = (TIME_ZONE_ID_DAYLIGHT == tzid );

		// calculate difference between Bias of previous & new timezones
		OldBias = m_tziCurrent.Bias + (m_fInDST? m_tziCurrent.DaylightBias : m_tziCurrent.StandardBias);
		NewBias = m_tziSelected.Bias + (m_fInDST ? m_tziSelected.DaylightBias : m_tziSelected.StandardBias);

		// Since UTC=Local+Bias, NewLocal=OldLocal+(OldBias-NewBias)

		GetLocalTime(&stOld);
		SystemTimeToFileTime(&stOld, (FILETIME*)&ftOld);
	        
		ftNew = ftOld + (((__int64)(OldBias-NewBias)) * FILETIME_TO_MINUTES);
		FileTimeToSystemTime((FILETIME*)&ftNew, &stNew);

		// now update the clock
		SetLocalTime(&stNew);
		// update our notion of "current" timezone
		SetTimeZoneInformation(&m_tziSelected);  
	}
}


BOOL APIENTRY DllMain( HANDLE  hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

